//
//  StatisticsComputator.h
//  GPUProcessingTesting
//
//  Created by kadlubek47 on 19.08.2013.
//  Copyright (c) 2013 kadlubek47. All rights reserved.
//

#ifndef GPUProcessingTesting_StatisticsComputator_h
#define GPUProcessingTesting_StatisticsComputator_h

#include "TrialsSet.h"
#include <algorithm>    // std::sort
#include <sstream>


class StatisticsComputator {
public:
    
    class Linear {
    public:
        double minimum              = -1;
        double quartile1            = -1;
        double median               = -1;
        double quartile3            = -1;
        double maximum              = -1;
        
        operator std::string() { std::stringstream s; s << "( " << minimum << ", " << quartile1 << ", " << median << ", " << quartile3 << ", " << maximum << ")"; return s.str(); }
    };
    
    class Average {
    public:
        double average              = -1;
        double stantard_deviation   = -1;
        
        operator std::string() { std::stringstream s; s << "( " << average << ", " << stantard_deviation << ")"; return s.str(); }
    };
    
    class OnTime {
    public:
        double all;
        double onTime               = -1;
        double onTime_percentage    = -1;
        
        operator std::string() { std::stringstream s; s << "(" << onTime << "/" << all << ", " << onTime_percentage << ")"; return s.str(); }
    };
    
    static void compute (TrialsSet& trialsSet) {
        
        //Result, sortedTrials
        Linear  result_linear;
        Average result_average;
        OnTime  result_ontime;
        
        
        
        size_t numOfTrials = result_ontime.all = trialsSet.get_trialsNumber();
        std::vector<double> sortedTrials = trialsSet.get_trials();
        std::sort ( sortedTrials.begin(), sortedTrials.end() );
        //.
        
        //averageTrialValue
        double sum = 0;
        for(size_t trialNum = 0; trialNum < numOfTrials; ++trialNum )
            sum += trialsSet.get_trial( trialNum );
        
        result_average.average = sum / (double)numOfTrials;
        //.
        
        //minimal, median, maximum, quartile1, quartile3
        result_linear.minimum      = sortedTrials[0];
        result_linear.quartile1    = sortedTrials[numOfTrials/4];
        result_linear.median       = sortedTrials[numOfTrials/2];
        result_linear.quartile3    = sortedTrials[numOfTrials*3/4];
        result_linear.maximum      = sortedTrials[numOfTrials-1];
        //.
        
        //numOfBlocksOnTime
        unsigned int blockSize = boost::any_cast<unsigned int> (    trialsSet.properties_.get(Properties::block_size).first      );
        unsigned int sampleRate= boost::any_cast<unsigned int> (    trialsSet.properties_.get(Properties::sample_rate).first     );
    
        double latencyValue = (double) blockSize /  (double) sampleRate * 1000 /*ms*/;
        result_ontime.onTime = 0;
        for(size_t trialNum = 0; trialNum < numOfTrials; ++trialNum )
            if( trialsSet.get_trial( trialNum ) < latencyValue )
                ++result_ontime.onTime;
        
        result_ontime.onTime_percentage = (double)result_ontime.onTime / (double)numOfTrials * 100 ;
        //.
        
        
        trialsSet.properties_.add               (Properties::statistics_latency,   latencyValue);
        trialsSet.properties_.add_user_struct   (Properties::statistics_linear,    result_linear);
        trialsSet.properties_.add_user_struct   (Properties::statistics_average,   result_average);
        trialsSet.properties_.add_user_struct   (Properties::statistics_ontime,    result_ontime);
    }
    
};


#endif
